package info.batcloud.fanli.core.service.impl;

import com.ctospace.archit.common.pagination.Paging;
import info.batcloud.fanli.core.dto.SellerPromotionItemDTO;
import info.batcloud.fanli.core.dto.SellerPromotionItemDepositOrderDTO;
import info.batcloud.fanli.core.constants.MessageKeyConstants;
import info.batcloud.fanli.core.entity.SellerPromotionItem;
import info.batcloud.fanli.core.entity.SellerPromotionItemDepositOrder;
import info.batcloud.fanli.core.entity.User;
import info.batcloud.fanli.core.enums.OrderPayType;
import info.batcloud.fanli.core.enums.SellerPromotionItemDepositOrderStatus;
import info.batcloud.fanli.core.enums.SellerPromotionItemStatus;
import info.batcloud.fanli.core.exception.BizException;
import info.batcloud.fanli.core.helper.PagingHelper;
import info.batcloud.fanli.core.repository.SellerPromotionItemDepositOrderRepository;
import info.batcloud.fanli.core.repository.SellerPromotionItemRepository;
import info.batcloud.fanli.core.repository.UserRepository;
import info.batcloud.fanli.core.service.OrderService;
import info.batcloud.fanli.core.service.SellerPromotionItemDepositOrderService;
import info.batcloud.fanli.core.service.SellerPromotionItemService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.*;

@Service
public class SellerPromotionItemDepositOrderServiceImpl implements SellerPromotionItemDepositOrderService, OrderService.OrderHandler<SellerPromotionItemDepositOrder> {

    @Inject
    private SellerPromotionItemService sellerPromotionItemService;

    @Inject
    private SellerPromotionItemRepository sellerPromotionItemRepository;

    @Inject
    private SellerPromotionItemDepositOrderRepository sellerPromotionItemDepositOrderRepository;

    @Inject
    private UserRepository userRepository;

    @Inject
    private OrderService orderService;

    @Override
    public void handlePayResult(SellerPromotionItemDepositOrder order, OrderService.PayResult payResult) {
        if (payResult.isSuccess()) {
            sellerPromotionItemService.addPromotionNum(order.getSellerPromotionItemId(), order.getNum(), order.getTotalFee());
        }
    }

    @Override
    public OrderService.CheckPayResult checkPay(SellerPromotionItemDepositOrder order) {
        OrderService.CheckPayResult result = new OrderService.CheckPayResult();
        if (order.getStatus() != SellerPromotionItemDepositOrderStatus.WAIT_PAY) {
            result.setSuccess(false);
            result.setCode(MessageKeyConstants.ORDER_STATUS_IS_NOT_WAIT_PAY);
        } else {
            result.setSuccess(true);
        }
        return result;
    }

    @Override
    public String getContent(SellerPromotionItemDepositOrder order) {
        return "宝贝推广保证金充值，数量：" + order.getNum() + "个，宝贝ID:" + order.getSellerPromotionItemId();
    }

    @Override
    public String getTitle(SellerPromotionItemDepositOrder order) {
        return "宝贝推广保证金充值，数量：" + order.getNum() + "个，宝贝ID:" + order.getSellerPromotionItemId();
    }

    @Override
    public String getStatusTitle(SellerPromotionItemDepositOrder order) {
        return order.getStatus().getTitle();
    }

    @Override
    public boolean isCanPay(SellerPromotionItemDepositOrder order) {
        //只有上架或者下架状态的宝贝才可以支付
        SellerPromotionItemDTO spi = sellerPromotionItemService.findById(order.getSellerPromotionItemId());
        if (spi.getStatus() != SellerPromotionItemStatus.ONSALE && spi.getStatus() != SellerPromotionItemStatus.INSTOCK) {
            return false;
        }
        return order.getStatus() == SellerPromotionItemDepositOrderStatus.WAIT_PAY;
    }

    @Override
    public void createTransferOrder(TransferOrderCreateParam param) {
        int existsNum = sellerPromotionItemDepositOrderRepository
                .countBySellerPromotionItemIdAndStatus(param.getSellerPromotionItemId(),
                        SellerPromotionItemDepositOrderStatus.TRANSFER_WAIT_VERIFY);
        if (existsNum > 0) {
            throw new BizException(MessageKeyConstants.SELLER_PROMOTION_ITEM_DEPOSIT_ORDER_EXISTS);
        }
        if (sellerPromotionItemDepositOrderRepository.countByAlipayTransferTradeNo(param.getAlipayTransferTradeNo().trim()) != 0) {
            throw new BizException(MessageKeyConstants.ALIPAY_TRADE_NO_EXISTS);
        }

        SellerPromotionItem spi = sellerPromotionItemRepository.findOne(param.getSellerPromotionItemId());
        Assert.isTrue(param.getUserId().equals(spi.getUserId()), "");
        SellerPromotionItemDepositOrder order = new SellerPromotionItemDepositOrder();
        order.setNum(param.getNum());
        float totalFee = param.getNum() * spi.getRebateFee();
        order.setTotalFee(totalFee);
        order.setPaidFee(totalFee);
        order.setSellerPromotionItemId(spi.getId());
        order.setUserId(param.getUserId());
        order.setPayTime(new Date());
        order.setRebateFee(spi.getRebateFee());
        order.setPayType(OrderPayType.TRANSFER);
        order.setStatus(SellerPromotionItemDepositOrderStatus.TRANSFER_WAIT_VERIFY);
        order.setCreateTime(new Date());
        order.setAlipayTransferTradeNo(param.getAlipayTransferTradeNo());
        sellerPromotionItemDepositOrderRepository.save(order);
    }

    @Override
    @Transactional
    public void verify(long id, VerifyParam param) {
        SellerPromotionItemDepositOrder order = sellerPromotionItemDepositOrderRepository.findOne(id);
        if (param.isSuccess()) {
            order.setStatus(SellerPromotionItemDepositOrderStatus.PAID);
            sellerPromotionItemService.addPromotionNum(order.getSellerPromotionItemId(), order.getNum(), order.getPaidFee());
            sellerPromotionItemService.listById(order.getSellerPromotionItemId(), null);
        } else {
            order.setStatus(SellerPromotionItemDepositOrderStatus.VERIFY_FAIL);
        }
        order.setVerifyRemark(param.getVerifyRemark());
        sellerPromotionItemDepositOrderRepository.save(order);
    }

    @Override
    public Paging<SellerPromotionItemDepositOrderDTO> search(SearchParam param) {
        Specification<SellerPromotionItemDepositOrder> specification = (root, query, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressions = predicate.getExpressions();
            if (param.getStatus() != null) {
                expressions.add(cb.equal(root.get("status"), param.getStatus()));
            } else {
                expressions.add(cb.notEqual(root.get("status"), SellerPromotionItemDepositOrderStatus.DELETED));
            }
            if (param.getUserId() != null) {
                expressions.add(cb.equal(root.get("userId"), param.getUserId()));
            }
            if (param.getPayType() != null) {
                expressions.add(cb.equal(root.get("payType"), param.getPayType()));
            }
            if (StringUtils.isNotBlank(param.getAlipayTransferTradeNo())) {
                expressions.add(cb.equal(root.get("alipayTransferTradeNo"), param.getAlipayTransferTradeNo()));
            }
            if (param.getSellerPromotionItemId() != null) {
                expressions.add(cb.equal(root.get("sellerPromotionItemId"), param.getSellerPromotionItemId()));
            }
            return predicate;
        };
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        Pageable pageable = new PageRequest(param.getPage() - 1,
                param.getPageSize(), sort);
        Page<SellerPromotionItemDepositOrder> page = sellerPromotionItemDepositOrderRepository.findAll(specification, pageable);
        return PagingHelper.of(toBOList(page.getContent()), page.getTotalPages(), param.getPage(), param.getPageSize());
    }

    private List<SellerPromotionItemDepositOrderDTO> toBOList(List<SellerPromotionItemDepositOrder> list) {
        List<Long> userIds = new ArrayList<>();
        List<Long> sellerPromotionItemIds = new ArrayList<>();
        for (SellerPromotionItemDepositOrder order : list) {
            userIds.add(order.getUserId());
            sellerPromotionItemIds.add(order.getSellerPromotionItemId());
        }
        Iterable<User> userList = userRepository.findByIdIn(userIds);
        Map<Long, User> userMap = new HashMap<>();
        Map<Long, SellerPromotionItem> itemMap = new HashMap<>();
        userList.forEach(u -> userMap.put(u.getId(), u));

        Iterable<SellerPromotionItem> itemIterator = sellerPromotionItemRepository.findAll(sellerPromotionItemIds);
        itemIterator.forEach(i -> itemMap.put(i.getId(), i));
        List<SellerPromotionItemDepositOrderDTO> boList = new ArrayList<>();
        for (SellerPromotionItemDepositOrder order : list) {
            SellerPromotionItemDepositOrderDTO bo = new SellerPromotionItemDepositOrderDTO();
            BeanUtils.copyProperties(order, bo);
            User user = userMap.get(order.getUserId());
            bo.setUserId(user.getId());
            bo.setUserPhone(user.getPhone());
            SellerPromotionItem spi = itemMap.get(order.getSellerPromotionItemId());
            bo.setSellerPromotionItemId(spi.getId());
            bo.setSellerPromotionItemPicUrl(spi.getPicUrl());
            bo.setSellerPromotionItemShopTitle(spi.getShopTitle());
            bo.setRebateFee(order.getRebateFee());
            bo.setSellerPromotionItemPrice(spi.getPrice());
            bo.setSellerPromotionItemOriginPrice(spi.getOriginPrice());
            bo.setSellerPromotionItemUrl(spi.getSourceItemUrl());
            bo.setSellerPromotionItemTitle(spi.getTitle());
            bo.setSellerPromotionItemEcomPlat(spi.getEcomPlat());
            boList.add(bo);
        }
        return boList;
    }
}
